package main

import (
	"flag"
	"github.com/shurcooL/github_flavored_markdown"
	"log"
	"net/http"
	"strings"
	"io/ioutil"
	"os"
	"regexp"
	"fmt"
	"github.com/shurcooL/github_flavored_markdown/gfmstyle"
	"bufio"
)

var addr = flag.String("addr", ":8002", "address to listen on")
var mode = flag.String("mode", "local", "local mode or http mode")
var dataServerUrl = flag.String("dataserver", "http://localhost:8003/", "the dataServerUrl server")
var dataRoot = flag.String("root", "/var/www/markdown", "the data root dir")

var validPath = regexp.MustCompile(`^/([/_\-a-zA-Z0-9\x{4e00}-\x{9fa5}]+)\.md$`)

func getHttpFile(w http.ResponseWriter, r *http.Request) ([]byte, error) {
	md := *dataServerUrl + strings.Replace(r.URL.Path, ".md", "", -1) + ".md"
	log.Printf("try to get " + md)
	resp, err := http.Get(md)
	if err != nil {
		http.Error(w, fmt.Sprintf("Err:\n%s.\nreq path:%s\n", err.Error(), r.URL.Path), http.StatusInternalServerError)
		return nil, err
	}
	if resp.StatusCode != 200 {
		http.Error(w, fmt.Sprintf("Err:\nstatusCode: %d\nreq path:%s\n", resp.StatusCode, r.URL.Path), http.StatusInternalServerError)
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	return body, err
}

func getLocalFile(w http.ResponseWriter, r *http.Request) ([]byte, error) {
	md := strings.Replace(r.URL.Path, ".md", "", -1) + ".md"
	md = strings.Replace(md, "..", "", -1)
	mdPath := *dataRoot + md
	log.Printf("try to get " + md)
	body, err := ioutil.ReadFile(mdPath)
	if err != nil {
		return nil, fmt.Errorf("failed to get content of: %s\n", md)
	}
	return body, nil
}

func renderMarkdownHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html;charset=UTF-8")
	m := validPath.FindStringSubmatch(r.URL.Path)
	if m == nil {
		http.Error(w, fmt.Sprintf("not a valid path: %s\n", r.URL.Path), http.StatusNotAcceptable)
		return
	}

	var body []byte
	var err error
	if *mode == "http" {
		body, err = getHttpFile(w, r)
	} else {
		body, err = getLocalFile(w, r)
	}

	if err != nil {
		w.Write([]byte("<pre>Err:\n" + err.Error() + "</pre>"))
		log.Printf(err.Error())
		return
	}

	bo := bufio.NewWriter(w)
	bo.WriteString(`<html>
<head><meta charset="utf-8">
<title></title>
<link href="/assets/gfm.css" media="all" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/octicons/2.1.2/octicons.css" media="all" rel="stylesheet" type="text/css" />
</head>
<body>
<article class="markdown-body entry-content" style="padding: 30px;">`)
	bo.Write(github_flavored_markdown.Markdown(body))
	bo.WriteString(`</article></body></html>`)
	bo.Flush()
}

func main() {
	log.SetOutput(os.Stdout)
	flag.Parse()
	http.HandleFunc("/", renderMarkdownHandler)
	// Serve the "/assets/gfm.css" file.
	http.Handle("/assets/", http.StripPrefix("/assets", http.FileServer(gfmstyle.Assets)))

	data := *dataRoot
	if (*mode == "http") {
		data = *dataServerUrl
	}

	log.Printf("server started.  listen to: %s, work mode: %s, data: %s\n", *addr, *mode, data)
	e := http.ListenAndServe(*addr, nil)
	if e != nil {
		log.Fatal("ListenAndServe: ", e)
	}
}
